package concurrent.masterandworker;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @description: 任务接收及分配
 * @author: kanggw
 * @date: 2023/7/3
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Accessors(chain = true)
public class Master<T extends Task, R> {

    private LinkedBlockingQueue<Task> taskQueue = new LinkedBlockingQueue<>();
    private HashMap<String,Worker<T,R>> workers;

    private Map<String,R> results = new ConcurrentHashMap<>();

    private AtomicLong sum = new AtomicLong(0);

    public Master(int workerCount) {
        this.workers = new HashMap<>();
        for (int i = 0; i <= workerCount; i++) {
            Worker<T,R> worker = new Worker();
            workers.put("worker节点：" +worker.getWorkerId(), worker);
        }
        Thread thread = new Thread(this::run);
        thread.start();
    }

    private void run() {
        for (; ; ) {
            for (Worker worker : workers.values()) {
                //取任务交给worker
                try {
                    Task task = taskQueue.take();
                    worker.submit(task, this::resultCallBack);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public void submitMaster(T task) {
        try {
            taskQueue.put(task);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private void resultCallBack(Object obj) {
        Task<R> task = (Task<R>) obj;
        String taskName = "任务id:" + task.getTaskId() + "工作节点id:"+ task.getWorkerId();
        this.results.put(taskName, task.getResult());
        sum.getAndAdd((Integer)task.getResult());
    }

    public void printResult() {
        System.out.println("sum:" + sum);
        for (Map.Entry<String, R> entry : results.entrySet()) {
            System.out.println("任务：" + entry.getKey() +",结果：" + entry.getValue());
        }
    }


}
